function resolveElement(
  el: HTMLElement | SVGElement | Window | Document | null | undefined,
): HTMLElement | SVGElement | null | undefined {
  if (typeof Window !== 'undefined' && el instanceof Window) return el.document.documentElement
  if (typeof Document !== 'undefined' && el instanceof Document) return el.documentElement
  return el as HTMLElement | SVGElement | null | undefined
}

export interface IConfig {
  distance?: number
  direction?: 'top' | 'bottom' | 'left' | 'right'
  interval?: number
  offset?: any
}

/**
 * 无限滚动 \ 滚动加载
 * @param element box元素
 * @param onLoadMore 加载函数
 * @param options 配置
 * @returns
 */
export function useInfiniteScroll(
  element: Ref<HTMLElement | SVGElement | Window | Document | null | undefined>,
  onLoadMore: (state: any) => void,
  options: IConfig = {},
) {
  const { direction = 'bottom', interval = 100 } = options

  const state = reactive(
    useScroll(element, {
      ...options,
      offset: {
        [direction]: options.distance ?? 0,
        ...options.offset,
      },
    }),
  )

  const promise = ref<any>()
  const isClose = ref<boolean>(false)

  const isLoading = computed(() => !!promise.value)

  const observedElement = computed<HTMLElement | SVGElement | null | undefined>(() => {
    return resolveElement(toValue(element))
  })

  const isElementVisible = useElementVisibility(observedElement)

  function checkAndLoad() {
    console.log('RUN:CHECK_AND_LOAD')
    state.measure()

    if (!observedElement.value || !isElementVisible.value) return

    const { scrollHeight, clientHeight, scrollWidth, clientWidth } = observedElement.value as HTMLElement
    const isNarrower =
      direction === 'bottom' || direction === 'top' ? scrollHeight <= clientHeight : scrollWidth <= clientWidth

    if (state.arrivedState[direction] || isNarrower) {
      if (!promise.value) {
        promise.value = Promise.all([
          onLoadMore(state),
          new Promise((resolve) => setTimeout(resolve, interval)),
        ]).finally(() => {
          if (isClose.value) return
          promise.value = null
          nextTick(() => checkAndLoad())
        })
      }
    }
  }

  const _watch = watch([() => state.arrivedState[direction], () => isElementVisible.value], checkAndLoad, {
    immediate: true,
  })

  function stop() {
    isClose.value = true
    _watch()
  }
  return {
    isLoading,
    isClose,
    stop,
  }
}
